library(tidyverse)
── Attaching packages ───────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.1.0       ✔ purrr   0.3.2  
✔ tibble  2.1.1       ✔ dplyr   0.8.0.1
✔ tidyr   0.8.3       ✔ stringr 1.4.0  
✔ readr   1.3.1       ✔ forcats 0.4.0  
── Conflicts ──────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(ggvoronoi)
library(viridis)
Loading required package: viridisLite
library(ggthemes)
library(cluster)
library(igraph)

Attaching package: ‘igraph’

The following objects are masked from ‘package:dplyr’:

    as_data_frame, groups, union

The following objects are masked from ‘package:purrr’:

    compose, simplify

The following object is masked from ‘package:tidyr’:

    crossing

The following object is masked from ‘package:tibble’:

    as_data_frame

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union
library(readxl)

set.seed(1234)
similitud <- read_csv('results/similitud_LP_2016.csv',col_types = cols(SITC = col_character()))
clasificacion <-read_xlsx("../LDA/names/classifications_hidalgo.xlsx", sheet = 'sitc_product_id') %>% 
  rename(medioide=sitc_product_code)
M <- as.matrix(similitud[,-1])
#distance matrix
DM <- 1/M

K medioids


plot_pam_giant_graph <- function(M,pam_clust,threshold = 0.5){
  
#grafo
adj_mat <- M
#pongo un threshold
adj_mat[adj_mat<threshold] <- 0

g  <- graph_from_adjacency_matrix(adj_mat, weighted=TRUE,mode='undirected')

graphs <- decompose.graph(g)
comp_gigante <- graphs[[which.max(sapply(graphs, vcount))]]

# Pongo solo la etiqueta de los medioides

names <- V(comp_gigante)$name
mediod_label <- names
ind <- which(!mediod_label %in% pam_clust$medoids) 
mediod_label[ind]<-NA
V(comp_gigante)$label <- mediod_label

colors <- tibble(cluster = unique(pam_clust$clustering), color = colorspace::rainbow_hcl(length(unique(pam_clust$clustering)),c = 100, l = 60, start = 0,alpha = 0.75))

colors_df <- tibble(names) %>% 
  left_join(.,tibble(names = names(pam_clust$clustering),cluster = pam_clust$clustering)) %>% 
  left_join(colors)

V(comp_gigante)$color <- colors_df$color

l <-layout_nicely(comp_gigante)

plot(comp_gigante,edge.arrow.size=.4,vertex.frame.color="#ffffff", edge.size = .1,
     vertex.label=V(comp_gigante)$label, vertex.label.color="black",vertex.size = 5,
     vertex.label.cex=1.2,  layout=l)

}

Max spanning tree

plot_pam_max_span <- function(M,pam_clust,threshold = 0.5){
  
#grafo
adj_mat <- M
#pongo un threshold
# adj_mat[adj_mat<threshold] <- 0

g  <- graph_from_adjacency_matrix(adj_mat, weighted=TRUE)

g_mst <- mst(g)  
# Pongo solo la etiqueta de los medioides

names <- V(g_mst)$name
mediod_label <- names
ind <- which(!mediod_label %in% pam_clust$medoids) 
mediod_label[ind]<-NA
V(g_mst)$label <- mediod_label

colors <- tibble(cluster = unique(pam_clust$clustering), color = colorspace::rainbow_hcl(length(unique(pam_clust$clustering)),c = 100, l = 60, start = 0,alpha = 0.75))

colors_df <- tibble(names) %>% 
  left_join(.,tibble(names = names(pam_clust$clustering),cluster = pam_clust$clustering)) %>% 
  left_join(colors)

V(g_mst)$color <- colors_df$color

g_mst <-  decompose.graph(g_mst)[[1]]

# l <-layout_nicely(g_mst)

plot(g_mst,edge.arrow.size=.4,vertex.frame.color="#ffffff", edge.size = .1,
     vertex.label=V(g_mst)$label, vertex.label.color="black",vertex.size = 5,
     vertex.label.cex=1.2)#,  layout=l)

}

pam k=2

plot_pam_giant_graph(M,pam_clust2)
Joining, by = "names"
Joining, by = "cluster"

pam k=10

pam_clust10 <- pam(DM,diss = TRUE,k=10)

png('results/pam10_gigant_lp.png',width = 6,height = 6, units = 'in', res = 300)
plot_pam_giant_graph(M,pam_clust10)
Joining, by = "names"
Joining, by = "cluster"
dev.off()
null device 
          1 
png('results/pam10_mst_lp.png',width = 6,height = 6, units = 'in', res = 300)
plot_pam_max_span(M,pam_clust10)
Joining, by = "names"
Joining, by = "cluster"
dev.off()
null device 
          1 

pam k=50

pam_clust50 <- pam(DM,diss = TRUE,k=50)

png('results/pam50_gigant_lp.png',width = 6,height = 6, units = 'in', res = 300)
plot_pam_giant_graph(M,pam_clust50)
Joining, by = "names"
Joining, by = "cluster"
dev.off()
null device 
          1 
png('results/pam50_mst_lp.png',width = 6,height = 6, units = 'in', res = 300)
plot_pam_max_span(M,pam_clust50)
Joining, by = "names"
Joining, by = "cluster"
dev.off()
null device 
          1 


tibble(k = '2', medioide= pam_clust2$medoids) %>% 
  # bind_rows(tibble(k = '10', medioide= pam_clust10$medoids)) %>% 
  # bind_rows(tibble(k = 50, medioide= pam_clust50$medoids)) %>% 
  left_join(clasificacion %>% select(-id)) %>% 
  xtable::xtable(., caption='Medioides', label='table:pam') %>% 
  xtable::print.xtable(.,include.rownames=FALSE)
Joining, by = "medioide"
% latex table generated in R 3.5.1 by xtable 1.8-3 package
% Sat Apr 13 17:40:10 2019
\begin{table}[ht]
\centering
\begin{tabular}{lll}
  \hline
k & medioide & sitc\_product\_name\_short\_en \\ 
  \hline
2 & 0589 & Fruit prepared or preserved, nes \\ 
  2 & 7413 & Industrial and laboratory furnaces and ovens, etc, parts, nes \\ 
   \hline
\end{tabular}
\caption{Medioides} 
\label{table:pam}
\end{table}
  tibble(k = '10', medioide= pam_clust10$medoids) %>%
  left_join(clasificacion %>% select(-id)) %>% 
  xtable::xtable(., caption='Medioides', label='table:pam') %>% 
  xtable::print.xtable(.,include.rownames=FALSE)
Joining, by = "medioide"
% latex table generated in R 3.5.1 by xtable 1.8-3 package
% Sat Apr 13 17:40:34 2019
\begin{table}[ht]
\centering
\begin{tabular}{lll}
  \hline
k & medioide & sitc\_product\_name\_short\_en \\ 
  \hline
10 & 6911 & Structures and parts of, of iron, steel; plates, rods, and the like \\ 
  10 & 0542 & Beans, peas, other leguminous vegetables, dried, shelled \\ 
  10 & 0116 & Edible offal of headings 0011-5 and 0015, fresh, chilled or frozen \\ 
  10 & 8452 & Outerwear knitted or crocheted, not elastic nor rubberized; womens, girls, infants, suits, dresses, etc, knitted, crocheted \\ 
  10 & 7429 & Parts, nes of pumps and liquids elevators falling in heading 742 \\ 
  10 & 0721 & Cocoa beans, raw, roasted \\ 
  10 & 6536 & Fabrics, woven, 85\% plus of discontinuous regenerated fibres \\ 
  10 & 5827 & Silicones \\ 
  10 & 2816 & Iron ore agglomerates \\ 
  10 & 7764 & Electronic microcircuits \\ 
   \hline
\end{tabular}
\caption{Medioides} 
\label{table:pam}
\end{table}

tibble(k = '50', medioide= pam_clust50$medoids) %>%
  left_join(clasificacion) %>% 
  xtable::xtable(., caption='Medioides', label='table:pam') %>% 
  xtable::print.xtable(.,include.rownames=FALSE)
Joining, by = "medioide"
% latex table generated in R 3.5.1 by xtable 1.8-3 package
% Sat Apr 13 17:40:36 2019
\begin{table}[ht]
\centering
\begin{tabular}{llrl}
  \hline
k & medioide & id & sitc\_product\_name\_short\_en \\ 
  \hline
50 & 0484 & 696.00 & Bakery products \\ 
  50 & 6115 & 995.00 & Sheep and lamb skin leather \\ 
  50 & 0113 & 658.00 & Pig meat fresh, chilled or frozen \\ 
  50 & 5542 & 949.00 & Organic surface-active agents, nes \\ 
  50 & 0116 & 661.00 & Edible offal of headings 0011-5 and 0015, fresh, chilled or frozen \\ 
  50 & 2686 & 813.00 & Waste of sheep's or lambs' wool, or of other animal hair, nes \\ 
  50 & 6635 & 1094.00 & Wool; expanding or insulating mineral materials, nes \\ 
  50 & 0565 & 706.00 & Vegetables, prepared or preserved, nes \\ 
  50 & 0344 & 677.00 & Fish fillets, frozen \\ 
  50 & 0412 & 683.00 & Other wheat and meslin, unmilled \\ 
  50 & 2221 & 762.00 & Groundnuts, green \\ 
  50 & 7132 & 1189.00 & Motor vehicles piston engines, headings: 722; 78; 74411 and 95101 \\ 
  50 & 0542 & 699.00 & Beans, peas, other leguminous vegetables, dried, shelled \\ 
  50 & 0571 & 707.00 & Oranges, mandarins, etc, fresh or dried \\ 
  50 & 0611 & 720.00 & Sugars, beet and cane, raw, solid \\ 
  50 & 6536 & 1051.00 & Fabrics, woven, 85\% plus of discontinuous regenerated fibres \\ 
  50 & 2483 & 785.00 & Wood, non-coniferous species, sawn, planed, tongued, grooved, etc \\ 
  50 & 4242 & 888.00 & Palm oil \\ 
  50 & 0742 & 733.00 & Mate \\ 
  50 & 8435 & 1358.00 & Womens, girls, infants outerwear, textile, not knitted or crocheted; blouses \\ 
  50 & 6744 & 1127.00 & Sheet, plates, rolled of thickness 4,75mm plus, of iron or steel \\ 
  50 & 2640 & 798.00 & Jute, other textile bast fibres, nes, raw, processed but not spun \\ 
  50 & 5827 & 964.00 & Silicones \\ 
  50 & 6594 & 1081.00 & Carpets, rugs, mats, of wool or fine animal hair \\ 
  50 & 6330 & 1012.00 & Cork manufactures \\ 
  50 & 2518 & 790.00 & Chemical wood pulp, sulphite \\ 
  50 & 6511 & 1036.00 & Silk yarn and spun from noil or waste; silkworm gut \\ 
  50 & 6516 & 1041.00 & Yarn containing less than 85\% of discontinuous synthetic fibres \\ 
  50 & 2655 & 802.00 & Manila hemp, raw or processed but not spun, its tow and waste \\ 
  50 & 7369 & 1234.00 & Parts, nes of and accessories for machine-tools of heading 736 \\ 
  50 & 5623 & 953.00 & Mineral or chemical fertilizer, potassic \\ 
  50 & 6911 & 1159.00 & Structures and parts of, of iron, steel; plates, rods, and the like \\ 
  50 & 3222 & 860.00 & Other coal, not agglomerated \\ 
  50 & 6672 & 1114.00 & Diamonds (non-industrial), not mounted or set \\ 
  50 & 2875 & 843.00 & Zinc ores and concentrates \\ 
  50 & 2816 & 836.00 & Iron ore agglomerates \\ 
  50 & 5241 & 928.00 & Radio-active chemical elements, isotopes etc \\ 
  50 & 5225 & 923.00 & Inorganic bases and metallic oxides, hydroxides and peroxides \\ 
  50 & 2881 & 847.00 & Ash and residues, nes \\ 
  50 & 8481 & 1373.00 & Articles of apparel, clothing accessories of leather \\ 
  50 & 3341 & 866.00 & Gasoline and other light oils \\ 
  50 & 5162 & 916.00 & Aldehyde, ketone and quinone-function compounds \\ 
  50 & 7269 & 1224.00 & Parts, nes of machines falling within headings 72631, 7264, 7267 \\ 
  50 & 7492 & 1262.00 & Cocks, valves and similar appliances, for pipes boiler shells, etc \\ 
  50 & 7757 & 1301.00 & Domestic electro-mechanical appliances; and parts thereof, nes \\ 
  50 & 7245 & 1213.00 & Weaving, knitting, etc, machines, machines for preparing yarns, etc \\ 
  50 & 7763 & 1305.00 & Diodes, transistors, photocells, etc \\ 
  50 & 7628 & 1280.00 & Other radio receivers \\ 
  50 & 7525 & 1272.00 & Peripheral units, including control and adapting units \\ 
  50 & 7144 & 1193.00 & Reaction engines \\ 
   \hline
\end{tabular}
\caption{Medioides} 
\label{table:pam}
\end{table}

heatmap


m2 <- similitud
#m2[,-1][lower.tri(m2[,-1],diag = TRUE)] <- NA

sim_table <- m2 %>% 
  gather(SITC_par,value = similarity,2:ncol(.)) %>%
  filter(!is.na(similarity)) %>% 
  mutate(distance = 1/similarity)

sim_table %>% 
  arrange(-similarity) %>% 
  top_n(10, similarity) %>%
  left_join(clasificacion %>% select(SITC= medioide, description=sitc_product_name_short_en)) %>% 
  left_join(clasificacion %>% select(SITC_par= medioide, description_par=sitc_product_name_short_en)) %>% 
  mutate(description = paste0(substr(description,1,22),'...'),
         description_par = paste0(substr(description_par,1,22),'...')) %>% 
  xtable::xtable(., caption='Productos más similares', label='table:similarity') %>% 
  xtable::print.xtable(.,include.rownames=FALSE)
Joining, by = "SITC"
Joining, by = "SITC_par"
% latex table generated in R 3.5.1 by xtable 1.8-3 package
% Sat Apr 13 18:07:13 2019
\begin{table}[ht]
\centering
\begin{tabular}{llrll}
  \hline
SITC & SITC\_par & similarity & description & description\_par \\ 
  \hline
8423 & 8439 & 0.83 & Men's and boys' outerw... & Womens, girls, infants... \\ 
  8431 & 8434 & 0.83 & Womens, girls, infants... & Womens, girls, infants... \\ 
  8433 & 8434 & 0.82 & Womens, girls, infants... & Womens, girls, infants... \\ 
  8459 & 8462 & 0.82 & Outerwear knitted or c... & Under-garments, knitte... \\ 
  8434 & 8435 & 0.81 & Womens, girls, infants... & Womens, girls, infants... \\ 
  8433 & 8435 & 0.80 & Womens, girls, infants... & Womens, girls, infants... \\ 
  8421 & 8424 & 0.80 & Men's and boys' outerw... & Men's and boys' outerw... \\ 
  8451 & 8459 & 0.80 & Outerwear knitted or c... & Outerwear knitted or c... \\ 
  8421 & 8431 & 0.80 & Men's and boys' outerw... & Womens, girls, infants... \\ 
  8422 & 8424 & 0.79 & Men's and boys' outerw... & Men's and boys' outerw... \\ 
   \hline
\end{tabular}
\caption{Productos más similares} 
\label{table:similarity}
\end{table}
mean_sim_table %>% 
  arrange(-similarity) %>%
  top_n(25, similarity) %>% 
  filter(row_number() %% 2 == 0) %>% 
  left_join(clasificacion %>% select(SITC=medioide,SITC_desc=Description)) %>% 
  left_join(clasificacion %>% select(SITC_par=medioide,SITC_par_desc=Description)) %>% 
  select(similarity,SITC, SITC_desc,SITC_par,SITC_par_desc) %>% 
  mutate(SITC_desc = tolower(SITC_desc),
         SITC_par_desc = tolower(SITC_par_desc),
         SITC_desc = str_remove(SITC_desc,",x-knit"),
         SITC_par_desc = str_remove(SITC_par_desc,",x-knit"),
         SITC_desc = str_remove(SITC_desc,".xknit"),
         SITC_par_desc = str_remove(SITC_par_desc,".xknit"),
         SITC_desc = str_remove(SITC_desc,".knit"),
         SITC_par_desc = str_remove(SITC_par_desc,".knit")) %>% 
  xtable::xtable(., caption='Productos más similares', label='table:similarity') %>% 
  xtable::print.xtable(.,include.rownames=FALSE)
LS0tCnRpdGxlOiAiU2ltaWxpdHVkIGFuYWx5c2lzIFNlcmllIGxhcmdhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKYGBge3Igc2V0dXB9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdndm9yb25vaSkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGNsdXN0ZXIpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KHJlYWR4bCkKCnNldC5zZWVkKDEyMzQpCmBgYAoKYGBge3J9CnNpbWlsaXR1ZCA8LSByZWFkX2NzdigncmVzdWx0cy9zaW1pbGl0dWRfTFBfMjAxNi5jc3YnLGNvbF90eXBlcyA9IGNvbHMoU0lUQyA9IGNvbF9jaGFyYWN0ZXIoKSkpCmNsYXNpZmljYWNpb24gPC1yZWFkX3hsc3goIi4uL0xEQS9uYW1lcy9jbGFzc2lmaWNhdGlvbnNfaGlkYWxnby54bHN4Iiwgc2hlZXQgPSAnc2l0Y19wcm9kdWN0X2lkJykgJT4lIAogIHJlbmFtZShtZWRpb2lkZT1zaXRjX3Byb2R1Y3RfY29kZSkKCgpgYGAKCmBgYHtyfQpNIDwtIGFzLm1hdHJpeChzaW1pbGl0dWRbLC0xXSkKI2Rpc3RhbmNlIG1hdHJpeApETSA8LSAxL00KCmBgYAoKCiMgSyBtZWRpb2lkcwoKYGBge3J9CgpwbG90X3BhbV9naWFudF9ncmFwaCA8LSBmdW5jdGlvbihNLHBhbV9jbHVzdCx0aHJlc2hvbGQgPSAwLjUpewogIAojZ3JhZm8KYWRqX21hdCA8LSBNCiNwb25nbyB1biB0aHJlc2hvbGQKYWRqX21hdFthZGpfbWF0PHRocmVzaG9sZF0gPC0gMAoKZyAgPC0gZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KGFkal9tYXQsIHdlaWdodGVkPVRSVUUsbW9kZT0ndW5kaXJlY3RlZCcpCgpncmFwaHMgPC0gZGVjb21wb3NlLmdyYXBoKGcpCmNvbXBfZ2lnYW50ZSA8LSBncmFwaHNbW3doaWNoLm1heChzYXBwbHkoZ3JhcGhzLCB2Y291bnQpKV1dCgojIFBvbmdvIHNvbG8gbGEgZXRpcXVldGEgZGUgbG9zIG1lZGlvaWRlcwoKbmFtZXMgPC0gVihjb21wX2dpZ2FudGUpJG5hbWUKbWVkaW9kX2xhYmVsIDwtIG5hbWVzCmluZCA8LSB3aGljaCghbWVkaW9kX2xhYmVsICVpbiUgcGFtX2NsdXN0JG1lZG9pZHMpIAptZWRpb2RfbGFiZWxbaW5kXTwtTkEKVihjb21wX2dpZ2FudGUpJGxhYmVsIDwtIG1lZGlvZF9sYWJlbAoKY29sb3JzIDwtIHRpYmJsZShjbHVzdGVyID0gdW5pcXVlKHBhbV9jbHVzdCRjbHVzdGVyaW5nKSwgY29sb3IgPSBjb2xvcnNwYWNlOjpyYWluYm93X2hjbChsZW5ndGgodW5pcXVlKHBhbV9jbHVzdCRjbHVzdGVyaW5nKSksYyA9IDEwMCwgbCA9IDYwLCBzdGFydCA9IDAsYWxwaGEgPSAwLjc1KSkKCmNvbG9yc19kZiA8LSB0aWJibGUobmFtZXMpICU+JSAKICBsZWZ0X2pvaW4oLix0aWJibGUobmFtZXMgPSBuYW1lcyhwYW1fY2x1c3QkY2x1c3RlcmluZyksY2x1c3RlciA9IHBhbV9jbHVzdCRjbHVzdGVyaW5nKSkgJT4lIAogIGxlZnRfam9pbihjb2xvcnMpCgpWKGNvbXBfZ2lnYW50ZSkkY29sb3IgPC0gY29sb3JzX2RmJGNvbG9yCgpsIDwtbGF5b3V0X25pY2VseShjb21wX2dpZ2FudGUpCgpwbG90KGNvbXBfZ2lnYW50ZSxlZGdlLmFycm93LnNpemU9LjQsdmVydGV4LmZyYW1lLmNvbG9yPSIjZmZmZmZmIiwgZWRnZS5zaXplID0gLjEsCiAgICAgdmVydGV4LmxhYmVsPVYoY29tcF9naWdhbnRlKSRsYWJlbCwgdmVydGV4LmxhYmVsLmNvbG9yPSJibGFjayIsdmVydGV4LnNpemUgPSA1LAogICAgIHZlcnRleC5sYWJlbC5jZXg9MS4yLCAgbGF5b3V0PWwpCgp9CgpgYGAKCiMjIyBNYXggc3Bhbm5pbmcgdHJlZQoKYGBge3J9CnBsb3RfcGFtX21heF9zcGFuIDwtIGZ1bmN0aW9uKE0scGFtX2NsdXN0LHRocmVzaG9sZCA9IDAuNSl7CiAgCiNncmFmbwphZGpfbWF0IDwtIE0KI3BvbmdvIHVuIHRocmVzaG9sZAojIGFkal9tYXRbYWRqX21hdDx0aHJlc2hvbGRdIDwtIDAKCmcgIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeChhZGpfbWF0LCB3ZWlnaHRlZD1UUlVFKQoKZ19tc3QgPC0gbXN0KGcpICAKIyBQb25nbyBzb2xvIGxhIGV0aXF1ZXRhIGRlIGxvcyBtZWRpb2lkZXMKCm5hbWVzIDwtIFYoZ19tc3QpJG5hbWUKbWVkaW9kX2xhYmVsIDwtIG5hbWVzCmluZCA8LSB3aGljaCghbWVkaW9kX2xhYmVsICVpbiUgcGFtX2NsdXN0JG1lZG9pZHMpIAptZWRpb2RfbGFiZWxbaW5kXTwtTkEKVihnX21zdCkkbGFiZWwgPC0gbWVkaW9kX2xhYmVsCgpjb2xvcnMgPC0gdGliYmxlKGNsdXN0ZXIgPSB1bmlxdWUocGFtX2NsdXN0JGNsdXN0ZXJpbmcpLCBjb2xvciA9IGNvbG9yc3BhY2U6OnJhaW5ib3dfaGNsKGxlbmd0aCh1bmlxdWUocGFtX2NsdXN0JGNsdXN0ZXJpbmcpKSxjID0gMTAwLCBsID0gNjAsIHN0YXJ0ID0gMCxhbHBoYSA9IDAuNzUpKQoKY29sb3JzX2RmIDwtIHRpYmJsZShuYW1lcykgJT4lIAogIGxlZnRfam9pbiguLHRpYmJsZShuYW1lcyA9IG5hbWVzKHBhbV9jbHVzdCRjbHVzdGVyaW5nKSxjbHVzdGVyID0gcGFtX2NsdXN0JGNsdXN0ZXJpbmcpKSAlPiUgCiAgbGVmdF9qb2luKGNvbG9ycykKClYoZ19tc3QpJGNvbG9yIDwtIGNvbG9yc19kZiRjb2xvcgoKZ19tc3QgPC0gIGRlY29tcG9zZS5ncmFwaChnX21zdClbWzFdXQoKIyBsIDwtbGF5b3V0X25pY2VseShnX21zdCkKCnBsb3QoZ19tc3QsZWRnZS5hcnJvdy5zaXplPS40LHZlcnRleC5mcmFtZS5jb2xvcj0iI2ZmZmZmZiIsIGVkZ2Uuc2l6ZSA9IC4xLAogICAgIHZlcnRleC5sYWJlbD1WKGdfbXN0KSRsYWJlbCwgdmVydGV4LmxhYmVsLmNvbG9yPSJibGFjayIsdmVydGV4LnNpemUgPSA1LAogICAgIHZlcnRleC5sYWJlbC5jZXg9MS4yKSMsICBsYXlvdXQ9bCkKCn0KYGBgCgoKIyMjIHBhbSBrPTIKCmBgYHtyfQpwYW1fY2x1c3QyIDwtIHBhbShETSxkaXNzID0gVFJVRSxrPTIpCgpwbmcoJ3Jlc3VsdHMvcGFtMl9naWdhbnRfbHAucG5nJyx3aWR0aCA9IDYsaGVpZ2h0ID0gNiwgdW5pdHMgPSAnaW4nLCByZXMgPSAzMDApCnBsb3RfcGFtX2dpYW50X2dyYXBoKE0scGFtX2NsdXN0MikKZGV2Lm9mZigpCgpwbmcoJ3Jlc3VsdHMvcGFtMl9tc3RfbHAucG5nJyx3aWR0aCA9IDYsaGVpZ2h0ID0gNiwgdW5pdHMgPSAnaW4nLCByZXMgPSAzMDApCnBsb3RfcGFtX21heF9zcGFuKE0scGFtX2NsdXN0MikKZGV2Lm9mZigpCmBgYAoKIyMjIHBhbSBrPTEwCgpgYGB7cn0KcGFtX2NsdXN0MTAgPC0gcGFtKERNLGRpc3MgPSBUUlVFLGs9MTApCgpwbmcoJ3Jlc3VsdHMvcGFtMTBfZ2lnYW50X2xwLnBuZycsd2lkdGggPSA2LGhlaWdodCA9IDYsIHVuaXRzID0gJ2luJywgcmVzID0gMzAwKQpwbG90X3BhbV9naWFudF9ncmFwaChNLHBhbV9jbHVzdDEwKQpkZXYub2ZmKCkKCnBuZygncmVzdWx0cy9wYW0xMF9tc3RfbHAucG5nJyx3aWR0aCA9IDYsaGVpZ2h0ID0gNiwgdW5pdHMgPSAnaW4nLCByZXMgPSAzMDApCnBsb3RfcGFtX21heF9zcGFuKE0scGFtX2NsdXN0MTApCmRldi5vZmYoKQpgYGAKCiMjIyBwYW0gaz01MAoKYGBge3J9CnBhbV9jbHVzdDUwIDwtIHBhbShETSxkaXNzID0gVFJVRSxrPTUwKQoKcG5nKCdyZXN1bHRzL3BhbTUwX2dpZ2FudF9scC5wbmcnLHdpZHRoID0gNixoZWlnaHQgPSA2LCB1bml0cyA9ICdpbicsIHJlcyA9IDMwMCkKcGxvdF9wYW1fZ2lhbnRfZ3JhcGgoTSxwYW1fY2x1c3Q1MCkKZGV2Lm9mZigpCgpwbmcoJ3Jlc3VsdHMvcGFtNTBfbXN0X2xwLnBuZycsd2lkdGggPSA2LGhlaWdodCA9IDYsIHVuaXRzID0gJ2luJywgcmVzID0gMzAwKQpwbG90X3BhbV9tYXhfc3BhbihNLHBhbV9jbHVzdDUwKQpkZXYub2ZmKCkKYGBgCgoKYGBge3J9CnRpYmJsZShrID0gJzInLCBtZWRpb2lkZT0gcGFtX2NsdXN0MiRtZWRvaWRzKSAlPiUgCiAgIyBiaW5kX3Jvd3ModGliYmxlKGsgPSAnMTAnLCBtZWRpb2lkZT0gcGFtX2NsdXN0MTAkbWVkb2lkcykpICU+JSAKICAjIGJpbmRfcm93cyh0aWJibGUoayA9IDUwLCBtZWRpb2lkZT0gcGFtX2NsdXN0NTAkbWVkb2lkcykpICU+JSAKICBsZWZ0X2pvaW4oY2xhc2lmaWNhY2lvbiAlPiUgc2VsZWN0KC1pZCkpICU+JSAKICB4dGFibGU6Onh0YWJsZSguLCBjYXB0aW9uPSdNZWRpb2lkZXMnLCBsYWJlbD0ndGFibGU6cGFtJykgJT4lIAogIHh0YWJsZTo6cHJpbnQueHRhYmxlKC4saW5jbHVkZS5yb3duYW1lcz1GQUxTRSkKYGBgCgpgYGB7cn0KICB0aWJibGUoayA9ICcxMCcsIG1lZGlvaWRlPSBwYW1fY2x1c3QxMCRtZWRvaWRzKSAlPiUKICBsZWZ0X2pvaW4oY2xhc2lmaWNhY2lvbiAlPiUgc2VsZWN0KC1pZCkpICU+JSAKICB4dGFibGU6Onh0YWJsZSguLCBjYXB0aW9uPSdNZWRpb2lkZXMnLCBsYWJlbD0ndGFibGU6cGFtJykgJT4lIAogIHh0YWJsZTo6cHJpbnQueHRhYmxlKC4saW5jbHVkZS5yb3duYW1lcz1GQUxTRSkKYGBgCgpgYGB7cn0KCnRpYmJsZShrID0gJzUwJywgbWVkaW9pZGU9IHBhbV9jbHVzdDUwJG1lZG9pZHMpICU+JQogIGxlZnRfam9pbihjbGFzaWZpY2FjaW9uKSAlPiUgCiAgeHRhYmxlOjp4dGFibGUoLiwgY2FwdGlvbj0nTWVkaW9pZGVzJywgbGFiZWw9J3RhYmxlOnBhbScpICU+JSAKICB4dGFibGU6OnByaW50Lnh0YWJsZSguLGluY2x1ZGUucm93bmFtZXM9RkFMU0UpCmBgYAoKCiMgaGVhdG1hcAoKYGBge3J9CgpkaW0oZGlzdChNKSkKaGMgPC0gaGNsdXN0KGRpc3QoTSkpCnBsb3QoaGMpCgpjbHVzdF9jb2wgPC0gZnVuY3Rpb24oTSkgewogIE1bTTwwLjVdIDwtIDAKICBETV90aHIgPC0gMS9NCiAgRE1fdGhyW2lzLmluZmluaXRlKERNX3RocildIDwtIDk5OQogIGQgPC0gZGlzdChETV90aHIpCiAgaGNsdXN0KGQsbWV0aG9kID0gIndhcmQuRCIpCn0KCgpoZWF0bWFwKE0sIHN5bW0gPSAgVFJVRSwgY29sID0gdmlyaWRpcygyNTYpLCBoY2x1c3RmdW4gPSBjbHVzdF9jb2wpCgpgYGAKCgpgYGB7cn0KCm0yIDwtIHNpbWlsaXR1ZAojbTJbLC0xXVtsb3dlci50cmkobTJbLC0xXSxkaWFnID0gVFJVRSldIDwtIE5BCgpzaW1fdGFibGUgPC0gbTIgJT4lIAogIGdhdGhlcihTSVRDX3Bhcix2YWx1ZSA9IHNpbWlsYXJpdHksMjpuY29sKC4pKSAlPiUKICBmaWx0ZXIoIWlzLm5hKHNpbWlsYXJpdHkpKSAlPiUgCiAgbXV0YXRlKGRpc3RhbmNlID0gMS9zaW1pbGFyaXR5KQoKYGBgCgpgYGB7cn0KCmdncGxvdChzaW1fdGFibGUsYWVzKFNJVEMsIHJlb3JkZXIoU0lUQ19wYXIsIGRlc2MoU0lUQ19wYXIpKSwgZmlsbCA9IHNpbWlsYXJpdHkpKSsKICBnZW9tX3RpbGUoKSsKICAjIHNjYWxlX3hfZGlzY3JldGUoYnJlYWtzID0gbmFtZXNbc2VxKDEsbGVuZ3RoKG5hbWVzKSwxMDApXSkrCiAgIyBzY2FsZV95X2Rpc2NyZXRlKGJyZWFrcyA9IG5hbWVzW3NlcSgxLGxlbmd0aChuYW1lcyksMTAwKV0pKwogICMgdGhlbWVfdHVmdGUoKSsKICB0aGVtZV92b2lkKCkrCiAgbGFicyh4PScnLHk9JycsZmlsbD0iUHJveGltaXR5IikrCiAgc2NhbGVfZmlsbF92aXJpZGlzKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpCgpnZ3NhdmUoJ3Jlc3VsdHMvaGVhdG1hcF9wcm94X3NpdGNPcmRfbHAucG5nJyxoZWlnaHQgPSA2LHdpZHRoID0gNixkcGkgPSAzMDApCgpgYGAKCgpgYGB7cn0KTV90aHIgPC0gTQojIE1fdGhyW01fdGhyPDAuNV0gPC0gMAoKRE1fdGhyIDwtIDEvTV90aHIKRE1fdGhyW2lzLmluZmluaXRlKERNX3RocildIDwtIDk5OTk5OTk5OTk5CmQgPC0gYXMuZGlzdChETV90aHIpCgpjbHVzdGVyX2ggPC0gaGNsdXN0KCBkLCBtZXRob2QgPSAid2FyZC5EIiApCgpvcmRlciA8LSBjbHVzdGVyX2gkb3JkZXIKCm9yZGVyZWRfbmFtZXMgPC0gY29sbmFtZXMoRE1fdGhyKVtvcmRlcl0KCnNpbV90YWJsZSAlPiUgCiAgbXV0YXRlKFNJVEMgPSBmYWN0b3IoU0lUQywgbGV2ZWxzID0gb3JkZXJlZF9uYW1lcyksCiAgICAgICAgIFNJVENfcGFyID0gZmFjdG9yKFNJVENfcGFyLCBsZXZlbHMgPSByZXYob3JkZXJlZF9uYW1lcykpCiAgICAgICAgICMgc2ltaWxhcml0eSA9IGNhc2Vfd2hlbihzaW1pbGFyaXR5PDAuNSB+MCwKICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfnNpbWlsYXJpdHkpCiAgICAgICAgICkgJT4lIApnZ3Bsb3QoLixhZXMoU0lUQywgU0lUQ19wYXIsIGZpbGwgPSBzaW1pbGFyaXR5KSkrCiAgZ2VvbV90aWxlKCkrCiAgIyBzY2FsZV94X2Rpc2NyZXRlKGJyZWFrcyA9IG9yZGVyZWRfbmFtZXNbc2VxKDEsbGVuZ3RoKG9yZGVyZWRfbmFtZXMpLDEwMCldKSsKICAjIHNjYWxlX3lfZGlzY3JldGUoYnJlYWtzID0gb3JkZXJlZF9uYW1lc1tzZXEoMSxsZW5ndGgob3JkZXJlZF9uYW1lcyksMTAwKV0pKwogIHRoZW1lX3ZvaWQoKSsKICBsYWJzKHg9JycseT0nJyxmaWxsPSJQcm94aW1pdHkiKSsKICBzY2FsZV9maWxsX3ZpcmlkaXMoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJykKCmdnc2F2ZSgncmVzdWx0cy9oZWF0bWFwX3Byb3hfQ2x1c3RPcmRfbHAucG5nJyxoZWlnaHQgPSA2LHdpZHRoID0gNixkcGkgPSAzMDApCgpgYGAKCgpgYGB7cn0KbTMgPC0gbTIKbTNbLC0xXVtsb3dlci50cmkobTNbLC0xXSxkaWFnID0gVFJVRSldIDwtIE5BCgoKc2ltX3RhYmxlIDwtIG0zICU+JSAKICBnYXRoZXIoU0lUQ19wYXIsdmFsdWUgPSBzaW1pbGFyaXR5LDI6bmNvbCguKSkgJT4lCiAgZmlsdGVyKCFpcy5uYShzaW1pbGFyaXR5KSkKYGBgCgpgYGB7cn0KCnNpbV90YWJsZSAlPiUgCiAgYXJyYW5nZSgtc2ltaWxhcml0eSkgJT4lIAogIHRvcF9uKDEwLCBzaW1pbGFyaXR5KSAlPiUKICBsZWZ0X2pvaW4oY2xhc2lmaWNhY2lvbiAlPiUgc2VsZWN0KFNJVEM9IG1lZGlvaWRlLCBkZXNjcmlwdGlvbj1zaXRjX3Byb2R1Y3RfbmFtZV9zaG9ydF9lbikpICU+JSAKICBsZWZ0X2pvaW4oY2xhc2lmaWNhY2lvbiAlPiUgc2VsZWN0KFNJVENfcGFyPSBtZWRpb2lkZSwgZGVzY3JpcHRpb25fcGFyPXNpdGNfcHJvZHVjdF9uYW1lX3Nob3J0X2VuKSkgJT4lIAogIG11dGF0ZShkZXNjcmlwdGlvbiA9IHBhc3RlMChzdWJzdHIoZGVzY3JpcHRpb24sMSwyMiksJy4uLicpLAogICAgICAgICBkZXNjcmlwdGlvbl9wYXIgPSBwYXN0ZTAoc3Vic3RyKGRlc2NyaXB0aW9uX3BhciwxLDIyKSwnLi4uJykpICU+JSAKICB4dGFibGU6Onh0YWJsZSguLCBjYXB0aW9uPSdQcm9kdWN0b3MgbcOhcyBzaW1pbGFyZXMnLCBsYWJlbD0ndGFibGU6c2ltaWxhcml0eScpICU+JSAKICB4dGFibGU6OnByaW50Lnh0YWJsZSguLGluY2x1ZGUucm93bmFtZXM9RkFMU0UpCgpgYGAKCmBgYHtyfQptZWFuX3NpbV90YWJsZSAlPiUgCiAgYXJyYW5nZSgtc2ltaWxhcml0eSkgJT4lCiAgdG9wX24oMjUsIHNpbWlsYXJpdHkpICU+JSAKICBmaWx0ZXIocm93X251bWJlcigpICUlIDIgPT0gMCkgJT4lIAogIGxlZnRfam9pbihjbGFzaWZpY2FjaW9uICU+JSBzZWxlY3QoU0lUQz1tZWRpb2lkZSxTSVRDX2Rlc2M9RGVzY3JpcHRpb24pKSAlPiUgCiAgbGVmdF9qb2luKGNsYXNpZmljYWNpb24gJT4lIHNlbGVjdChTSVRDX3Bhcj1tZWRpb2lkZSxTSVRDX3Bhcl9kZXNjPURlc2NyaXB0aW9uKSkgJT4lIAogIHNlbGVjdChzaW1pbGFyaXR5LFNJVEMsIFNJVENfZGVzYyxTSVRDX3BhcixTSVRDX3Bhcl9kZXNjKSAlPiUgCiAgbXV0YXRlKFNJVENfZGVzYyA9IHRvbG93ZXIoU0lUQ19kZXNjKSwKICAgICAgICAgU0lUQ19wYXJfZGVzYyA9IHRvbG93ZXIoU0lUQ19wYXJfZGVzYyksCiAgICAgICAgIFNJVENfZGVzYyA9IHN0cl9yZW1vdmUoU0lUQ19kZXNjLCIseC1rbml0IiksCiAgICAgICAgIFNJVENfcGFyX2Rlc2MgPSBzdHJfcmVtb3ZlKFNJVENfcGFyX2Rlc2MsIix4LWtuaXQiKSwKICAgICAgICAgU0lUQ19kZXNjID0gc3RyX3JlbW92ZShTSVRDX2Rlc2MsIi54a25pdCIpLAogICAgICAgICBTSVRDX3Bhcl9kZXNjID0gc3RyX3JlbW92ZShTSVRDX3Bhcl9kZXNjLCIueGtuaXQiKSwKICAgICAgICAgU0lUQ19kZXNjID0gc3RyX3JlbW92ZShTSVRDX2Rlc2MsIi5rbml0IiksCiAgICAgICAgIFNJVENfcGFyX2Rlc2MgPSBzdHJfcmVtb3ZlKFNJVENfcGFyX2Rlc2MsIi5rbml0IikpICU+JSAKICB4dGFibGU6Onh0YWJsZSguLCBjYXB0aW9uPSdQcm9kdWN0b3MgbcOhcyBzaW1pbGFyZXMnLCBsYWJlbD0ndGFibGU6c2ltaWxhcml0eScpICU+JSAKICB4dGFibGU6OnByaW50Lnh0YWJsZSguLGluY2x1ZGUucm93bmFtZXM9RkFMU0UpCgoKYGBgCgo=